﻿/*
 * MemoryStream.h
 */
#ifndef __GDK_MEMORYSTREAM_H__
#define __GDK_MEMORYSTREAM_H__

#include <gdk/core/Types.h>
#include <gdk/core/IO.h>
#include <gdk/core/MemoryBlock.h>
#include <gdk/core/File.h>
#include <gdk/core/Stream.h>
#include <gdk/core/Buffer.h>
#include <gdk/core/Log.h>
#include <gdk/core/Mutex.h>
#include <list>


namespace gdk
{


#define MEMORY_STREAM_BLOCK_SIZE          4096
#define MEMORY_STREAM_DEFAULT_CACHE_SIZE  (SSIZE_MAX - MEMORY_STREAM_BLOCK_SIZE) //(1024 * 1024 * 8)


class GDK_CORE_EXPORT MemoryStream : public IO
{
	DECLARE_CLASS_HANDLE(MemoryStream)
	DECLARE_CLASS_INSTANCE(MemoryStream)
	DECLARE_CLASS_INSTANCE1(MemoryStream, ssize_t)
	DECLARE_RT_CREATOR(MemoryStream)
	DECLARE_CLASS_SERIALIZE(MemoryStream)

public:
	class Cache : public IO
	{
		DECLARE_CLASS_HANDLE(Cache)

	public:
		enum ECacheType
		{
			MEMORY_CACHE,
			FILE_CACHE,
		};

	public:
		ECacheType const  _cacheType;

	protected:
		__INLINE__ Cache(ECacheType cacheType)
			: _cacheType(cacheType)
		{}

	private:
		__INLINE__ Cache& operator =(const Cache &r);

	public:
		virtual ssize_t getUseableBufferSize(void) const = 0;
	};

	class MemoryCache : public Cache
	{
		DECLARE_CLASS_HANDLE(MemoryCache)
		DECLARE_CLASS_INSTANCE(MemoryCache)

	private:
		typedef gdk::MemoryBlock<MEMORY_STREAM_BLOCK_SIZE>	MemoryBlock;

	private:
		MemoryBlock	mutable _buffer;
		ssize_t             _readPointer;
		ssize_t             _writePointer;

	private:
		__INLINE__ MemoryCache(void)
			: Cache(MEMORY_CACHE)
			, _readPointer(0)
			, _writePointer(0)
		{
		}

	public:
		__INLINE__ void  reset(void)
		{
			_readPointer = 0;
			_writePointer = 0;
		}
		__INLINE__ void setDataSize(ssize_t dataSize)
		{
			_writePointer = (dataSize <= 0 ? 0 : (dataSize >= MemoryBlock::MEMSIZE ? MemoryBlock::MEMSIZE : dataSize));
			if (_readPointer > _writePointer)
				_readPointer = _writePointer;
		}

	public:
		virtual ssize_t getUseableBufferSize(void) const;

	public:
		virtual ssize_t peek(void *buf, ssize_t size) const;
		virtual ssize_t available(void) const;
		virtual ssize_t read(void *buf, ssize_t size);
		virtual ssize_t write(const void *buf, ssize_t size);

	private:
		friend class MemoryStream;
	};

	class FileCache : public Cache
	{
		DECLARE_CLASS_HANDLE(FileCache)
		DECLARE_CLASS_INSTANCE2(FileCache, const SharedPtr<Mutex> &, File*)

	private:
		SharedPtr<Mutex>    _mutex;
		File::Handle const  _hFile;
		ssize_t             _beginPosition;
		ssize_t             _endPosition;
		ssize_t             _readPointer;
		ssize_t             _writePointer;

	private:
		FileCache(const SharedPtr<Mutex> &mutex, File *pFile);

	public:
		__INLINE__ void  reset(void)
		{
			_readPointer = _beginPosition;
			_writePointer = _beginPosition;
		}

	public:
		virtual ssize_t getUseableBufferSize(void) const;

	public:
		virtual ssize_t peek(void *buf, ssize_t size) const;
		virtual ssize_t available(void) const;
		virtual ssize_t read(void *buf, ssize_t size);
		virtual ssize_t write(const void *buf, ssize_t size);

	private:
		friend class MemoryStream;
	};

	class FileCacheFactory
	{
		typedef std::list<FileCache::Handle> FileCacheList;

	private:
		SharedPtr<Mutex>    _mutex;
		File::Handle        _hFile;
		ssize_t             _fileCacheSize;
		ssize_t             _totalFileCache;
		FileCacheList       _useableFileCacheList;

	public:
		FileCacheFactory(void);

	public:
		static FileCache::Handle writeToFileCache(MemoryCache *memCache);
		static void              freeFileCache(FileCache *fileCache);
	};
	typedef std::list<Cache::Handle>	CacheList;

private:
	CacheList	_cacheList; //数据块列表
	ssize_t		_dataSize;  //数据大小
	ssize_t		_memoryCacheCount; //当前高速内存缓存块数
	ssize_t		_maxMemCacheCount; //最大高速内存缓存块数


protected:
	MemoryStream(ssize_t memoryCacheSize = MEMORY_STREAM_DEFAULT_CACHE_SIZE);
	~MemoryStream(void);

public:
	virtual ssize_t available(void) const;
	virtual ssize_t peek(void *buf, ssize_t size) const;
	virtual ssize_t read(void *buf, ssize_t size);
	virtual ssize_t write(const void *data, ssize_t size);
};


template<typename TyIs>
TyIs& operator >>(TyIs &is, MemoryStream &o) __THROW1
{
	//清空MemoryStream的数据
	while (o.available() > 0)
	{
		char tmpBuf[MEMORY_STREAM_BLOCK_SIZE];
		o.read(tmpBuf, sizeof(tmpBuf));
	}

	//读取数据
	Buffer buf;
	is >> buf;

	//写入数据到MemoryStream
	o.write(buf.getBuffer(), buf.getBufferSize());
	return is;
}
template<typename TyOs>
TyOs& operator <<(TyOs &os, const MemoryStream &o) __THROW1
{
	ssize_t dataSize = o.available();
	Buffer buf(dataSize);
	if (dataSize != buf.getBufferSize()) __THROW__(__TEXT__("Alloc memory error!"));
	ssize_t result = o.peek(buf.getBuffer(), dataSize);
	if (result != dataSize) __THROW__(__TEXT__("peek data error!"));
	return os << buf;
}

template GDK_CORE_EXPORT InputStream& operator >>(InputStream &is, MemoryStream &o) __THROW1;
template GDK_CORE_EXPORT OutputStream& operator <<(OutputStream &os, const MemoryStream &o) __THROW1;



}//namespace gdk




#endif //__GDK_MEMORYSTREAM_H__
